Modifying Infrastructure
Everything below happens by editing the infrastructure-automation repo and running a make target — there's no manual Proxmox UI or SSH-and-hand-install step in the current process. See Getting Started first if you haven't set up access and tooling yet.
Who can run make
Every make target here runs Terraform and/or Ansible directly against production — there's no staging environment in between. Because of that, only admins run these commands directly on main.
If you're not an admin:
- Create a branch on
infrastructure-automationwith your changes (Terraform files, playbooks,inventory.ini,Makefiletargets, nginx vhosts, etc.). - Open a pull request and add an admin as a reviewer.
- An admin runs the relevant
maketarget (or merges and runs it) once the PR is approved.
Adding a new VM
- Add a resource block to a new
.tffile interraform/hetzner-main/, following the pattern of an existing VM (clonedebian-13-template, pick an unused VMID/IP, set cores/memory/disk). - Add a matching
setup-<name>.ymlplaybook underansible/hetzner-main/, and an entry ininventory.iniunder the appropriate host group. - Add the new host alias to your
~/.ssh/config(see Getting Started). - Add a target for it to the
Makefile, then run:This runsmake setup-<name>terraform apply(via thewaitdependency) to create the VM, then configures it with Ansible in one step.
See Provisioning with Terraform and Configuring with Ansible for the conventions to follow (Docker install pattern, deploy user, Grafana Alloy, UFW rules).
Adding a new application or public site
- Add a new directory under
ansible/hetzner-main/services-user-apps/orservices-staff-apps/(whichever VM it belongs on) containing the app'sdocker-compose.yml. - Add the app's name to the relevant
user_apps/staff_appslist in that VM's playbook, so it's picked up by theappstag. - Add an nginx vhost for it under
networking/nginx-config/in the automation repo. - Deploy:
Also arrange a DNS record for the new subdomain in Cloudflare before this will be publicly reachable.
make deploy-services-user-apps # or deploy-services-staff-apps
make update-webserver # pushes the new vhost + reloads nginx
Stateful apps (their own database, hand-placed secrets/data) get their own playbook tag instead of joining the shared apps tag — see the Gitea/Rocket.Chat pattern on the Services Staff page.
Adding software to an existing VM
Edit that VM's setup-<name>.yml playbook directly, then re-apply just the configuration (no Terraform involved):
make update-<name>
Opening a port / changing firewall rules
Edit the UFW tasks in the relevant playbook and re-run make update-<name>. Keep to the existing pattern — allow SSH, allow the webserver VM as ingress, deny everything else by default — unless there's a specific cross-VM reason not to (see Networking and Ingress).